package top.linyuxb.lycloud.rpc.starter.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import top.linyuxb.lycloud.common.constant.LyRpcRobinType;
import top.linyuxb.lycloud.rpc.starter.annotation.LyRpcReference;
import top.linyuxb.lycloud.rpc.starter.annotation.LyRpcRibbon;
import top.linyuxb.lycloud.rpc.starter.dto.LyRpcReferenceDto;
import top.linyuxb.lycloud.rpc.starter.dto.LyRpcRibbonDto;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

/**
 * Created by Intellij IDEA.
 *
 * @Author: linyuxb
 * @Date: 2024/6/5 10:28
 * @Desc: lyRpc bean后置处理器
 */
@Slf4j
public class LyRpcBeanPostProcessor implements BeanPostProcessor {
    /**
     * lyRpc客户端bean
     */
    private Map<String, Object> servers;

    public LyRpcBeanPostProcessor() {
    }

    public LyRpcBeanPostProcessor(Map<String, Object> servers) {
        this.servers = servers;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> objClz;
        if (AopUtils.isAopProxy(bean)) {
            objClz = AopUtils.getTargetClass(bean);
        } else {
            objClz = bean.getClass();
        }
        try {
            for (Field field : objClz.getDeclaredFields()) {
                //判断该字段是否有 Reference 注解
                LyRpcReference lyRpcReference = field.getAnnotation(LyRpcReference.class);
                if (Objects.nonNull(lyRpcReference)) {
                    // 存放调用版本
                    String app = lyRpcReference.app();
                    String env = lyRpcReference.env();
                    String version = lyRpcReference.version();
                    String key = objClz.getSimpleName() + "_" + field.getName();
                    LyRpcData.putLyRpcReference(key,
                            LyRpcReferenceDto.builder()
                                    .app(app)
                                    .env(env)
                                    .version(version)
                                    .build()
                    );
                    String name = field.getName();
                    Object o = servers.get(name);
                    if (Objects.nonNull(o)) {
                        field.setAccessible(true);
                        field.set(bean, o);
                    } else {
                        throw new BeanCreationException(beanName);
                    }
                }
            }
            for (Method method : objClz.getDeclaredMethods()) {
                LyRpcRibbon lyRpcRibbon = method.getAnnotation(LyRpcRibbon.class);
                if (Objects.nonNull(lyRpcRibbon)) {
                    // 存放调用版本
                    LyRpcRobinType ribbonType = lyRpcRibbon.ribbonType();
                    int timeOut = lyRpcRibbon.timeOut();
                    int retry = lyRpcRibbon.retry();
                    String fallbackMethod = lyRpcRibbon.fallbackMethod();
                    String key = objClz.getSimpleName() + "_" + method.getName();
                    LyRpcData.putRibbon(key, LyRpcRibbonDto.builder()
                            .ribbonType(ribbonType)
                            .timeOut(timeOut)
                            .retry(retry)
                            .fallbackMethod(fallbackMethod)
                            .build());
                }
            }
        } catch (Exception e) {
            throw new BeanCreationException(beanName, e);
        }
        return bean;
    }
}
